﻿using System;
using System.Configuration;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace PP.PortScanner
{
    public partial class MainForm : Form
    {
        private Configuration config = ConfigurationManager.OpenExeConfiguration(Application.ExecutablePath);
        private DateTime startTime;
        private Task[] tasks;
        private NotifyIcon notifyIcon;
        public MainForm()
        {
            InitializeComponent();

            //ThreadPool.SetMinThreads(50, 50) //出现开线程慢的问题
            ThreadPool.SetMinThreads(Environment.ProcessorCount * 2, Environment.ProcessorCount * 2);

            var now = DateTime.Now;
            this.Text = $"Hello 今天是{now.ToString("dddd")}哟 🤭";

            string ipOrDns = ConfigurationManager.AppSettings["IPOrDNS"].ToString();
            this.txt_IPOrDNS.Items.Add(ipOrDns);
            this.txt_IPOrDNS.SelectedIndex = 0;
            this.txt_PortStart.Text = ConfigurationManager.AppSettings["MinPortStart"].ToString();
            this.txt_PortEnd.Text = ConfigurationManager.AppSettings["MaxPortEnd"].ToString();
            this.txt_CoreNum.Text = $"CPU核心总数：{Environment.ProcessorCount}";

            this.components = new System.ComponentModel.Container();
            this.notifyIcon = new NotifyIcon(this.components);
            this.notifyIcon.Visible = true;
            this.notifyIcon.MouseClick += (sn, en) => { if (en.Button == MouseButtons.Left) this.Show(); };
            var menus = new ContextMenu();
            var menu1 = new MenuItem("退出软件");
            menu1.Click += (s1, e1) => { this.Close(); };
            menus.MenuItems.Add(menu1);
            notifyIcon.ContextMenu = menus;

            //20250123 新增局域网IP下拉选项
            _ = Task.Run(() =>
            {
                //获取本机IP 
                string _myHostIP = Dns.GetHostEntry(Dns.GetHostName()).AddressList.FirstOrDefault<IPAddress>(a => a.AddressFamily.ToString().Equals("InterNetwork")).ToString();
                //截取IP网段
                string ipDuan = _myHostIP.Remove(_myHostIP.LastIndexOf('.'));
                //枚举网段计算机
                Ping myPing = new Ping();
                byte[] buffer = Encoding.ASCII.GetBytes(string.Empty);
                for (int i = 1; i <= 255; i++)
                {
                    string pingIP = ipDuan + "." + i.ToString();
                    PingReply pingReply = myPing.Send(pingIP, 1000, buffer);
                    if (pingReply.Status == IPStatus.Success)
                    {
                        this?.Invoke(new Action(() =>
                        {
                            this.txt_IPOrDNS.Items.Add(pingIP);
                            this.groupBox1.Text = (i != 255) ? $"配置：{pingIP} ping OK" : "配置：";
                        }));
                    }
                    else
                    {
                        this?.Invoke(new Action(() =>
                        {
                            this.groupBox1.Text = (i != 255) ? $"配置：{pingIP} ping Fail" : "配置：";
                        }));
                    }
                }
            });

            //20250124 新增右键-全选、复制
            this.listBox_ActivePort.SelectionMode = this.listBox_NoActive.SelectionMode = SelectionMode.MultiExtended;
            this.MenuActive_SelectAll.Click += ContentMenu_Click;
            this.MenuActive_Copy.Click += ContentMenu_Click;
            this.MenuNoActive_SelectAll.Click += ContentMenu_Click;
            this.MenuNoActive_Copy.Click += ContentMenu_Click;
        }

        private void ContentMenu_Click(object sender, EventArgs e)
        {
            var menu = sender as ToolStripMenuItem;

            switch (menu.Name)
            {
                case nameof(MenuActive_SelectAll):
                    for (int i = listBox_ActivePort.Items.Count - 1; i >= 0; i--)
                    {
                        this.listBox_ActivePort.SetSelected(i, true);
                    }
                    break;

                case nameof(MenuActive_Copy):
                    Clipboard.SetDataObject(string.Join("\r\n", listBox_ActivePort.SelectedItems.Cast<string>()));
                    break;

                case nameof(MenuNoActive_SelectAll):
                    for (int i = listBox_NoActive.Items.Count - 1; i >= 0; i--)
                    {
                        this.listBox_NoActive.SetSelected(i, true);
                    }
                    break;

                case nameof(MenuNoActive_Copy):
                    Clipboard.SetDataObject(string.Join("\r\n", listBox_NoActive.SelectedItems.Cast<string>()));
                    break;

                default:
                    break;
            }

        }

        private void btn_Start_Click(object sender, EventArgs e)
        {
            string ipOrDns = this.txt_IPOrDNS.Text.Trim();
            string min = this.txt_PortStart.Text.Trim();
            string max = this.txt_PortEnd.Text.Trim();

            if (string.IsNullOrWhiteSpace(ipOrDns) || string.IsNullOrWhiteSpace(min) || string.IsNullOrWhiteSpace(max))
            {
                MessageBox.Show("不能为空！");
                return;
            }



            if (!int.TryParse(min, out var minPort) || !int.TryParse(max, out var maxPort))
            {
                MessageBox.Show("端口不是整数！");
                return;
            }

            config.AppSettings.Settings["IPOrDNS"].Value = ipOrDns;
            config.AppSettings.Settings["MinPortStart"].Value = min;
            config.AppSettings.Settings["MaxPortEnd"].Value = max;
            config.Save();
            ConfigurationManager.RefreshSection("appSettings");

            //20250124 新增域名解析成IP
            if (!IPAddress.TryParse(ipOrDns, out var targetIpAddress))
            {
                try
                {
                    targetIpAddress = Dns.GetHostEntry(ipOrDns).AddressList[0];
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"域名错误：{ex.Message}");
                    return;
                }
            }

            var ipadrlist = Dns.GetHostAddresses(Dns.GetHostName()).ToList();
            ipadrlist.Add(IPAddress.Parse("127.0.0.1"));
            ipadrlist.Add(IPAddress.Parse("0.0.0.0"));
            if (ipadrlist.Contains(targetIpAddress))
            {
                CheckLocalPort(minPort, maxPort);//本地IP
            }
            else
            {
                CheckRemotePort(targetIpAddress.ToString(), minPort, maxPort);//远程IP
            }
        }

        private void CheckLocalPort(int minPort, int maxPort)
        {
            btn_Start.Enabled = false;

            listBox_NoActive.Items.Clear();
            listBox_ActivePort.Items.Clear();
            startTime = DateTime.Now;
            int length = maxPort - minPort + 1;
            progressBar.Maximum = length;
            progressBar.Minimum = 0;

            var ips = IPGlobalProperties.GetIPGlobalProperties();
            var activeIps = ips.GetActiveTcpListeners().Select(p => p.Port).ToHashSet();

            _ = Task.Factory.StartNew(new Action(() =>
            {
                for (int i = minPort; i <= maxPort; i++)
                {
                    int port = i;
                    this?.Invoke(new Action(() =>
                    {
                        if (activeIps.Contains(port))
                        {
                            listBox_ActivePort.Items.Insert(0, port.ToString());
                            txt_Active.Text = $"激活端口总数：{listBox_ActivePort.Items.Count}";
                        }
                        else
                        {
                            listBox_NoActive.Items.Insert(0, port.ToString());
                            txt_NoActive.Text = $"未激活端口总数：{listBox_NoActive.Items.Count}";
                        }
                        progressBar.Value = listBox_ActivePort.Items.Count + listBox_NoActive.Items.Count;
                        txt_Progress.Text = $"{Math.Round(progressBar.Value / (double)progressBar.Maximum, 2) * 100}%";
                        txt_Progress.Visible = (txt_Progress.Text != "100%");
                        txt_Time.Text = $"耗时：{(DateTime.Now - startTime).TotalSeconds.ToString()}s";

                        //耗时操作卡死UI 处理方法
                        Application.DoEvents();
                    }));
                }

            })).ContinueWith(p => InitUI());

        }

        private void CheckRemotePort(string ip, int minPort, int maxPort)
        {
            btn_Start.Enabled = false;

            listBox_NoActive.Items.Clear();
            listBox_ActivePort.Items.Clear();
            startTime = DateTime.Now;
            int length = maxPort - minPort + 1;
            tasks = new Task[length];
            progressBar.Maximum = length;
            progressBar.Minimum = 0;

            _ = Task.Run(() =>
            {
                for (int i = minPort; i <= maxPort; i++)
                {
                    int port = i;
                    var task = Task.Factory.StartNew(new Action(() =>
                    {
                        var res = CheckRemotePortCanConnect(ip, port);
                        this?.Invoke(new Action(() =>
                        {
                            if (res.Item1)
                            {
                                listBox_ActivePort.Items.Insert(0, res.Item2);
                                txt_Active.Text = $"激活端口总数：{listBox_ActivePort.Items.Count}";
                            }
                            else
                            {
                                listBox_NoActive.Items.Insert(0, res.Item2);
                                txt_NoActive.Text = $"未激活端口总数：{listBox_NoActive.Items.Count}";
                            }
                            progressBar.Value = listBox_ActivePort.Items.Count + listBox_NoActive.Items.Count;
                            txt_Progress.Text = $"{Math.Round(progressBar.Value / (double)progressBar.Maximum, 2) * 100}%";
                            txt_Progress.Visible = (txt_Progress.Text != "100%");
                            txt_Time.Text = $"耗时：{(DateTime.Now - startTime).TotalSeconds.ToString()}s";

                            //耗时操作卡死UI 处理方法
                            Application.DoEvents();
                        }));
                    }));
                    tasks[i - minPort] = task;
                }

                Task.WaitAll(tasks);

            }).ContinueWith(p => InitUI());
        }

        private void InitUI()
        {
            this?.Invoke(new Action(() => { btn_Start.Enabled = true; }));
        }

        private (bool, string) CheckRemotePortCanConnect(string ipString, int port)
        {
            IPAddress ip = IPAddress.Parse(ipString);

            bool isConnect = false;

            TcpClient tcp = new TcpClient() { SendTimeout = 3 * 1000, ReceiveTimeout = 3 * 1000 };
            try
            {
                tcp.Connect(ip, port);
                isConnect = tcp.Connected;
            }
            catch (Exception)
            {
                isConnect = false;
            }
            finally
            {
                tcp?.Close();
                tcp?.Dispose();
            }
            return (isConnect, port.ToString());
        }
    }
}